from collections import defaultdict
from datetime import datetime
import pandas as pd


class ActionDetector:
    def __init__(self, df, window_size=5):
        self.df = df.copy()
        self.window_size = window_size  # 用于滑动窗口检测

    def preprocess(self, func_list):
        """预处理数据，包括时间转换和单位转换"""

        # 转换时间列
        feature_dict = defaultdict(list)
        self.df['csvTime'] = pd.to_datetime(self.df['csvTime'])
        self.df = self.df.sort_values('csvTime')

        # 使用 rolling 方法来创建滑动窗口
        # self.df.set_index('csvTime', inplace=True)
        self.df.reset_index(inplace=True)
        windows = self.df.rolling(window=self.window_size)

        # 存储满足条件的窗口的索引
        valid_indices = set()

        # 处理每个窗口
        for window_index, window in enumerate(windows):
            if len(window.dropna()) == self.window_size:
                for func in func_list:
                    sign, text = func(window)
                    if sign:
                        valid_indices.update(window.index)

                        feature_dict[list(window.index)[self.window_size // 2]].append(text)

        self.df['特征'] = ''
        for key, value in feature_dict.items():
            # if key in df.index:

            self.df.at[key, '特征'] = ','.join(value)
        # 根据索引去重并保留满足条件的窗口
        result_df = self.df.loc[sorted(valid_indices)].reset_index()
        return result_df



def process_data(json_input):
    # 解析JSON输入
    data = json_input["数据"]
    start_time = datetime.strptime(json_input["时间"]["开始"], "%Y-%m-%d %H:%M:%S")
    end_time = datetime.strptime(json_input["时间"]["结束"], "%Y-%m-%d %H:%M:%S")

    # 初始化一个空的DataFrame用于合并
    merged_df = None

    # 处理每个表
    for file_key, columns in data.items():
        # 读取CSV文件并选择指定列
        file_path = f'./data/{file_key}.csv'
        df = pd.read_csv(file_path, usecols=columns + ["csvTime"])

        # 将csvtime列转换为datetime类型
        df['csvTime'] = pd.to_datetime(df['csvTime'])

        # 将csvtime只保留到分钟部分
        df['csvTime'] = df['csvTime'].dt.strftime('%Y-%m-%d %H:%M')

        # 如果需要将csvTime转换回datetime类型
        df['csvTime'] = pd.to_datetime(df['csvTime'], format='%Y-%m-%d %H:%M')


        # 如果merged_df是None，直接赋值
        if merged_df is None:
            merged_df = df
        else:
            # 按照csvtime列进行连接
            merged_df = pd.merge(merged_df, df, on='csvTime', how='inner')

    if merged_df is not None:
        # 筛选出在指定时间范围内的数据
        filtered_df = merged_df[(merged_df['csvTime'] >= start_time) & (merged_df['csvTime'] <= end_time)]

        # 按照时间顺序排序
        sorted_df = filtered_df.sort_values(by='csvTime')
        sorted_df['P1_66'] = pd.to_numeric(sorted_df['P1_66'], errors='coerce').fillna(0)
        sorted_df['P1_75'] = pd.to_numeric(sorted_df['P1_75'], errors='coerce').fillna(0)
        sorted_df['P2_51'] = pd.to_numeric(sorted_df['P2_51'], errors='coerce').fillna(0)
        sorted_df['P2_60'] = pd.to_numeric(sorted_df['P2_60'], errors='coerce').fillna(0)

        # 进行加法操作
        sorted_df['P1_66'] = sorted_df['P1_66'] + sorted_df['P1_75'] #+ sorted_df['P2_51'] + sorted_df['P2_60']

        # 删除不需要的列
        del sorted_df['P1_75'], sorted_df['P2_51'], sorted_df['P2_60']
        return sorted_df
    else:
        # 如果没有数据进行合并，返回一个空的DataFrame
        return pd.DataFrame()


def detect_AjiaPowerON(window):
    try:
        conditions = [
            window.iloc[0]['Ajia-3_v'] == 'error' or window.iloc[0]['Ajia-5_v'] == 'error',
            window.iloc[1]['Ajia-3_v'] == 'error' or window.iloc[1]['Ajia-5_v'] == 'error',
            float(window.iloc[2]['Ajia-3_v']) >= 0 or float(window.iloc[2]['Ajia-5_v']) >= 0,
            float(window.iloc[3]['Ajia-3_v']) >= 0 or float(window.iloc[3]['Ajia-5_v']) >= 0,
            float(window.iloc[4]['Ajia-3_v']) >= 0 or float(window.iloc[4]['Ajia-5_v']) >= 0,
        ]
        return all(conditions), '`甲板工作启动`特征行'
    except Exception as e:
        return False, ''

def detect_AjiaPowerOFF(window):
    try:
        conditions = [

            float(window.iloc[0]['Ajia-3_v']) >= 0 and float(window.iloc[0]['Ajia-5_v']) >= 0,
            float(window.iloc[1]['Ajia-3_v']) >= 0 and float(window.iloc[1]['Ajia-5_v']) >= 0,
            float(window.iloc[2]['Ajia-3_v']) >= 0 and float(window.iloc[2]['Ajia-5_v']) >= 0,
            window.iloc[3]['Ajia-3_v'] == 'error' and window.iloc[3]['Ajia-5_v'] == 'error',
            window.iloc[4]['Ajia-3_v'] == 'error' and window.iloc[4]['Ajia-5_v'] == 'error',
        ]
        return all(conditions), '`甲板工作结束`特征行'
    except Exception as e:
        return False, ''


def detect_ONDP(window):
    try:
        conditions = [
            float(window.iloc[0]['P3_33']) == 0 or float(window.iloc[0]['P3_18']) == 0,
            float(window.iloc[1]['P3_33']) == 0 or float(window.iloc[1]['P3_18']) == 0,
            float(window.iloc[2]['P3_33']) > 0 or float(window.iloc[2]['P3_18']) > 0,
            float(window.iloc[3]['P3_33']) > 0 or float(window.iloc[3]['P3_18']) > 0,
            float(window.iloc[4]['P3_33']) > 0 or float(window.iloc[4]['P3_18']) > 0,
        ]
        return all(conditions), '`艏推开始工作`特征行'
    except Exception as e:
        return False, ''

def detect_OFFDP(window):
    try:
        conditions = [
            float(window.iloc[0]['P3_33']) > 0 or float(window.iloc[0]['P3_18']) > 0,
            float(window.iloc[1]['P3_33']) > 0 or float(window.iloc[1]['P3_18']) > 0,
            float(window.iloc[2]['P3_33']) == 0 or float(window.iloc[2]['P3_18']) == 0,
            float(window.iloc[3]['P3_33']) == 0 or float(window.iloc[3]['P3_18']) == 0,
            float(window.iloc[4]['P3_33']) == 0 or float(window.iloc[4]['P3_18']) == 0,
        ]
        return all(conditions), '`艏推工作结束`特征行'
    except Exception as e:
        return False, ''


def detect_QSQJ(window):
    '全速前进'
    try:
        conditions = [
            float(window.iloc[0]['P1_66']) <= 350,
            float(window.iloc[1]['P1_66']) <= 350,
            True,
            float(window.iloc[3]['P1_66']) >= 700 ,
            float(window.iloc[4]['P1_66']) >= 700 ,
        ]
        return all(conditions), '全速前进特征'
    except Exception as e:
        return False, ''

def detect_hangdu(window):

    try:
        # conditions = [
        #     float(window.iloc[0]['P1_66']) >= 800,
        #     float(window.iloc[1]['P1_66']) >= 700 ,
        #     float(window.iloc[2]['P1_66']) <= 500,
        #     float(window.iloc[3]['P1_66']) <= 500 ,
        #     float(window.iloc[4]['P1_66']) <= 500 ,
        # ]
        x1 = (float(window.iloc[3]['P1_66'])+float(window.iloc[4]['P1_66']))/(float(window.iloc[0]['P1_66'])+float(window.iloc[1]['P1_66']))<0.2
        x2 = float(window.iloc[3]['P1_66']) > 50 and float(window.iloc[4]['P1_66']) > 50
        return x1 and x2,'一号柴油发电机组有功功率测量突然变小，有可能是`航渡状态`结束'
    except Exception as e:
        # print('错了。',e)
        return False,''

def detect_tingbo4(window):
    '''停泊状态⾏'''
    try:
        conditions = [
            float(window.iloc[0]['P1_66']) == 0,
            float(window.iloc[1]['P1_66']) == 0,
            float(window.iloc[2]['P1_66']) > 0,
            float(window.iloc[3]['P1_66']) > 0,
            float(window.iloc[4]['P1_66']) > 0,
        ]
        return all(conditions), '一号柴油发电机组有功功率测量从0升高，可能停泊状态即将结束,如果接下来进入动力定位状态，则为`航渡状态`'
    except Exception as e:

        return False, ''


def detect_tingbo5(window):
    '''停泊状态⾏'''
    try:
        conditions = [
            float(window.iloc[0]['P1_66']) > 0,
            float(window.iloc[1]['P1_66']) > 0,
            float(window.iloc[2]['P1_66']) == 0,
            float(window.iloc[3]['P1_66']) == 0,
            float(window.iloc[4]['P1_66']) == 0,
        ]
        return all(conditions), '一号柴油发电机组有功功率测量转为0，如果动力定位刚刚结束，则已经进入停泊状态'
    except Exception as e:

        return False, ''


detect_list = [detect_AjiaPowerON,
               detect_ONDP,
               detect_OFFDP,
               detect_AjiaPowerOFF,
               detect_QSQJ,
               detect_hangdu,
               detect_tingbo4,
               detect_tingbo5
               ]

